www.gusucode.com > VC++写的C编译器源代码附设计文档-源码程序 > VC++写的C编译器源代码附设计文档-源码程序/code/C- Compiler/PCodeGenerator.cpp

    // PCodeGenerator.cpp : implementation file
// Download by http://www.NewXing.com

#include "stdafx.h"
#include "cminus.h"

#include "PCodeGenerator.h"

/*  *    CPCodeGenerator
    *    Construction & destruction
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.21             */

CPCodeGenerator::CPCodeGenerator( CString& str )
{
	m_pAnalyzer = new CAnalyzer( str );
	m_pProgram  = NULL;
	label		= 1;
}

CPCodeGenerator::~CPCodeGenerator()
{
	if( m_file.m_hFile != CFile::hFileNull ) m_file.Close();// close the output file
	if( m_pAnalyzer ) delete m_pAnalyzer;
	// DO NOT DELETE m_pProgram, it points to the tree in the m_pAnalyzer,
	// which has already been destructed above
}

/*  *    CPCodeGenerator
    *    Main routine, generating p-code
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.21             */

void CPCodeGenerator::GeneratePCode( LPCTSTR lpszPathName )
{
	m_pAnalyzer->TraceTypeCheck();
	if( bErrFlag ) {
		OutputPhaseMsg( "\r\nerrors occur, stop generating code!" );
		return;
	}
	m_pProgram = m_pAnalyzer->m_pProgram;
	ASSERT( m_pProgram != NULL );

	// create file
	CFileException e;
	if( !m_file.Open( lpszPathName, CFile::modeCreate | CFile::modeReadWrite, &e ) ) {
		OutputErrMsg( "failed to create file for code generation: %s", lpszPathName );
		return;
	}

	// generating p-code
	OutputPhaseMsg( "\r\ngenerating p-code..." );
	genPCode( m_pProgram );

	// close the file
	m_file.Close();
}

/*  *    CPCodeGenerator
    *    Help routines
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.21             */

// write comments to m_file, which must exist
void CPCodeGenerator::emitComment( char* format, ... )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	va_list params;
	static char buf[ 1024 ];
	buf[0] = ';';
	
	va_start( params, format );
	_vsnprintf( buf + 1, 1020, format, params );
	strcat( buf, "\r\n" );
	va_end( params );

	try {
		m_file.Write( buf, strlen(buf) );
	} catch( CFileException* ) {
		OutputErrMsg( "failed to write to file: %s", (LPCTSTR)m_file.GetFilePath() );
	}
}

// write codes to m_file, which must exist
void CPCodeGenerator::emitCode( char* format, ... )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	va_list params;
	static char buf[ 1024 ];
	buf[0] = '\t';
	
	va_start( params, format );
	_vsnprintf( buf + 1, 1020, format, params );
	strcat( buf, "\r\n" );
	va_end( params );

	try {
		m_file.Write( buf, strlen(buf) );
	} catch( CFileException* ) {
		OutputErrMsg( "failed to write to file: %s", (LPCTSTR)m_file.GetFilePath() );
	}
}

// add beginning "\t" & ending "/r/n" manually
void CPCodeGenerator::emitCode( CString& code )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	try {
		m_file.Write( (LPCTSTR)code, code.GetLength() );
	} catch( CFileException* ) {
		OutputErrMsg( "failed to write to file: %s", (LPCTSTR)m_file.GetFilePath() );
	}
}

/*  *    CPCodeGenerator
    *    private operations
  *	* *
   ***   Programer: 陆晓春
    *    Date:		2004.05.21             */

void CPCodeGenerator::genPCode( CTreeNode* t, BOOL addr, int lab1, int lab2 )
{
	ASSERT( m_file.m_hFile != CFile::hFileNull );

	CTreeNode* p = NULL;
	int i, _lab1, _lab2;
	CString temp = _T("");

	if( t == NULL ) return;

	switch( t->nodekind ) {
	case kFunDec:
		emitComment( "------------ Copyright 陆晓春, 2004 ------------" );
		emitComment( "start of function '%s %s(...)' declaration",
			         (LPCTSTR)ReservedKeywordList[(int)t->type], (LPCTSTR)t->szName );
		emitCode( "ent \t%s", (LPCTSTR)t->szName );
		genPCode( t->child[0], addr, lab1, lab2 );
		genPCode( t->child[1], addr, lab1, lab2 );
		emitCode( "ret" );
		emitComment( "end of function '%s %s(...)' declaration",
			         (LPCTSTR)ReservedKeywordList[(int)t->type], (LPCTSTR)t->szName );
		break;
	case kVarDec:
		if( t->bArray ) temp.Format( "[%d]", t->iArraySize );
		emitComment( "declaration: %s %s%s",
			         (LPCTSTR)ReservedKeywordList[(int)t->type], (LPCTSTR)t->szName, (LPCTSTR)temp );
//		if( t->szScope == "global" )
//			emitCode( "global\t%s%s:%s\t;global variable declaration",
//			          (LPCTSTR)t->szName, (LPCTSTR)temp, (LPCTSTR)ReservedKeywordList[(int)t->type] );
//		else
//			emitCode( "local\t%s%s:%s\t;local variable declaration",
//			          (LPCTSTR)t->szName, (LPCTSTR)temp, (LPCTSTR)ReservedKeywordList[(int)t->type] );
		break;
	case kParam:
		emitComment( "parameter: '%s %s%s'", 
					 (LPCTSTR)ReservedKeywordList[(int)t->type], (LPCTSTR)t->szName, (t->bArray ? "[]" : "") );
//		emitCode( "param\t%s%s:%s",
//			      (LPCTSTR)t->szName, (t->bArray ? "[]" : ""), (LPCTSTR)ReservedKeywordList[(int)t->type] );
		break;
	case kStmt:
		switch( t->kind.stmt ) {
		case kRead:
			emitComment( "read" );
			genPCode( t->child[0], TRUE, lab1, lab2 );
			switch( t->type ) {
			case _CHAR:		emitCode( "rdc\t;read a character from terminal" );	break;
			case _INT:		emitCode( "rdi\t;read an integer from terminal" );	break;
			case _FLOAT:	emitCode( "rdf\t;read a float number from terminal" );
			}
			break;
		case kWrite:
			emitComment( "write" );
			genPCode( t->child[0], addr, lab1, lab2 );
			switch( t->type ) {
			case _CHAR:		emitCode( "wrc\t;output a character to terminal" );	break;
			case _INT:		emitCode( "wri\t;output an integer to terminal" );	break;
			case _FLOAT:	emitCode( "wrf\t;output a float number to terminal"	);
			}
			break;
		case kPrintf:
			emitComment( "print \"%s\"", (LPCTSTR)t->szName );
			for( i = 0; i < t->szName.GetLength(); i++ ) {
				if( t->szName[i] == '\r' ) temp = "\\r";
				else if( t->szName[i] == '\n' ) temp = "\\n";
				else if( t->szName[i] == '\t' ) temp = "\\t";
				else if( t->szName[i] == '\a' ) temp = "\\a";
				else if( t->szName[i] == '\b' ) temp = "\\b";
				else if( t->szName[i] == '\f' ) temp = "\\f";
				else if( t->szName[i] == '\v' ) temp = "\\v";
				else temp.Format( "%c", t->szName[i] );
				emitCode( "ldcc\t'%s'", (LPCTSTR)temp );
				emitCode( "wrc\t;output a character to terminal" );
			}
			break;
		case kLabel:
			emitComment( "lab %s@%s", (LPCTSTR)t->szScope, (LPCTSTR)t->szName );
			emitCode( "lab \t%s@%s", (LPCTSTR)t->szScope, (LPCTSTR)t->szName );
			break;
		case kGoto:
			emitComment( "goto %s@%s", (LPCTSTR)t->szScope, (LPCTSTR)t->szName );
			emitCode( "ujp \t%s@%s", (LPCTSTR)t->szScope, (LPCTSTR)t->szName );
			break;
		case kIf:
			emitComment( "start of if statement" );
			emitComment( "if conditions" );
			genPCode( t->child[0], addr, lab1, lab2 );
			_lab1 = label++;
			emitCode( "fjp \tL%d", _lab1 );
			emitComment( "if statements" );
			genPCode( t->child[1], addr, lab1, lab2 );
			if( t->child[2] != NULL ) {
				_lab2 = label++;
				emitCode( "ujp \tL%d", _lab2 );
			}
			emitCode( "lab \tL%d", _lab1 );
			if( t->child[2] != NULL ) {
				emitComment( "else statements" );
				genPCode( t->child[2], addr, lab1, lab2 );
				emitCode( "lab \tL%d", _lab2 );
			}
			emitComment( "end of if statement" );
			break;
		case kWhile:
			emitComment( "start of while statement" );
			_lab1 = label++;
			emitCode( "lab \tL%d", _lab1 );
			emitComment( "while conditions" );
			genPCode( t->child[0], addr, lab1, lab2 );
			_lab2 = label++;
			emitCode( "fjp \tL%d", _lab2 );
			emitComment( "while statements" );
			genPCode( t->child[1], addr, _lab1, _lab2 );
			emitCode( "ujp \tL%d", _lab1 );
			emitCode( "lab \tL%d", _lab2 );
			emitComment( "end of while statement" );
			break;
		case kBreak:
			emitComment( "break statement" );
			emitCode( "ujp \tL%d", lab2 );
			break;
		case kContinue:
			emitComment( "continue statement" );
			emitCode( "ujp \tL%d", lab1 );
			break;
		case kReturn:
			emitComment( "return statement" );
			if( t->child[0] ) // return a value
				genPCode( t->child[0], addr, lab1, lab2 );
			else // void
				emitComment( "return void" );
			if( t->sibling || 
				(t->father && t->father->nodekind != kFunDec) )
				emitCode( "ret" );// not at the end of the routine, add "ret"
			break;
		case kCall:
			emitComment( "call '%s(...)'", (LPCTSTR)t->szName );
			emitCode( "mst" );
			if( t->child[0] ) // generate code of expressions in arguments
				genPCode( t->child[0], addr, lab1, lab2 );
			emitCode( "cup \t%s", (LPCTSTR)t->szName );
			emitComment( "end of call '%s(...)'", (LPCTSTR)t->szName );
		}
		break;
	case kExp:
		switch( t->kind.exp ) {
		case kConst:
			if( t->type == _CHARACTER ) 
				emitCode( "ldcc\t%s", (LPCTSTR)t->szName );
			else {
				if( t->szName.Find('.') == -1 ) // integer
					emitCode( "ldci\t%s", (LPCTSTR)t->szName );
				else // is float number
					emitCode( "ldcf\t%s", (LPCTSTR)t->szName );
			}
			break;
		case kID:
			if( t->bArray ) {
				emitCode( "lda \t%s", (LPCTSTR)t->szName );
				if( t->father && t->father->nodekind == kStmt && t->father->kind.stmt == kCall )
					break;// passing its base-address to the call function is OK
				genPCode( t->child[0], FALSE, lab1, lab2 );
				emitCode( "ixa \telem_size(%s)", (LPCTSTR)t->szName );
				if( !addr ) // load value
					emitCode( "ind \t0" );
			} else {
				if( addr ) // load address
					emitCode( "lda \t%s", (LPCTSTR)t->szName );
				else // load value
					emitCode( "lod \t%s", (LPCTSTR)t->szName );
			}
			break;
		case kOp:
			if( t->szName == "=" ) {
				genPCode( t->child[0], TRUE, lab1, lab2 );
				genPCode( t->child[1], FALSE, lab1, lab2 );
				p = t->father;
				if( (p && p->nodekind == kStmt && t == p->child[0]) ||
					(p && p->nodekind == kExp) )
					// t is a condition expression, or is in a expression,
					// keep the result in stack
					emitCode( "stn" );
				else // otherwise, pop it
					emitCode( "sto" );
			} else if( t->szName == "!" ) {
				genPCode( t->child[0], FALSE, lab1, lab2 );
				emitCode( "not" );
			} else {
				genPCode( t->child[0], FALSE, lab1, lab2 );
				genPCode( t->child[1], FALSE, lab1, lab2 );
				if( t->szName == "==" )
					emitCode( "equ \t;equal expression" );
				else if( t->szName == "!=" )
					emitCode( "neq \t;not equal expression" );
				else if( t->szName == "+" ) {
					if( t->type == _FLOAT ) emitCode( "adr \t;float add" );// float add
					else emitCode( "adi \t;integer add" );// integer add
				} else if( t->szName == "-" ) {
					if( t->type == _FLOAT ) emitCode( "sbr \t;float sub" );// float sub
					else emitCode( "sbi \t;integer sub" );// integer sub
				} else if( t->szName == "*" ) {
					if( t->type == _FLOAT ) emitCode( "mpr \t;float mul" );// float mul
					else emitCode( "mpi \t;integer mul" );// integer mul
				} else if( t->szName == "/" ) {
					if( t->type == _FLOAT ) emitCode( "dvr \t;float div" );// float div
					else emitCode( "dvi \t;integer div" );// integer div
				} else if( t->szName == "%" )
					emitCode( "mod \t;mod expression" );
				else if( t->szName == "<" )
					emitCode( "les \t;less than expression" );
				else if( t->szName == "<=" )
					emitCode( "leq \t;less than or equal expression" );
				else if( t->szName == ">" )
					emitCode( "grt \t;greater than expression" );
				else if( t->szName == ">=" )
					emitCode( "geq \t;greater than or equal expression" );
				else if( t->szName == "&&" )
					emitCode( "and \t;logical and expression" );
				else if( t->szName == "||" )
					emitCode( "or  \t;logical or expression" );
				else
					emitCode( "__error__" );
			}
		}
		break;
	default:
		emitCode( "__error__" );
	}

	if( t->sibling ) genPCode( t->sibling, addr, lab1, lab2 );
}